package com.wjh.anyview.aop;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wjh.anyview.util.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.ThreadContext;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Objects;
import java.util.UUID;

/**
 * 切入多个Controller类的关注点
 *
 * @author wjh
 * @date 2021/10/14 23:44
 * @Package com.panda.takeaway.aop
 */
@Aspect
@Component
@Slf4j
public class ControllerLogAspect {
    private final ObjectMapper mapper;

    @Autowired
    public ControllerLogAspect(ObjectMapper mapper) {
        this.mapper = mapper;
    }

    /**
     * 声明被切入点，标注“com.wjh.anyview.aop.annotation.ControllerLog”注解的方法将被切入
     */
    @Pointcut("execution(* com.wjh.anyview.controller..*.*(..))")
    public void controllerLog() {

    }

    /**
     * 注解@Before：方法执行前执行
     *
     * @param joinPoint 被切入点
     */
    @Before("controllerLog()")
    public void doBefore(JoinPoint joinPoint) {
        for (Object object : joinPoint.getArgs()) {
            //如果遍历的被切入点的参数是MultipartFile、HttpServletRequest、HttpServletResponse的实例
            if (object instanceof MultipartFile
                    || object instanceof HttpServletRequest
                    || object instanceof HttpServletResponse) {
                //跳出本次循环，执行下一次的循环
                continue;
            }
            try {
                HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
                //如果运行info日志级别输出
                if (log.isInfoEnabled()) {
                    //输出日志“被切入的位于的类名：joinPoint.getTarget().getClass().getName()，切入点的方法名：joinPoint.getSignature().getName()”
                    log.info(
                            "请求方式[" + request.getMethod() + "]" + " 客户端ip[" + HttpUtil.getIpAddress(request) + "]"+
                            " 访问接口[" +
                                    joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName()
                                    + "]的请求参数 : " + mapper.writeValueAsString(object)
                    );
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 注解@AfterReturning：方法返回结果后是执行
     *
     * @param response 要返回的变量的名称，这里指的是HttpServletResponse对象
     * @throws JsonProcessingException 抛出JsonProcessingException异常
     */
    @AfterReturning(returning = "response", pointcut = "controllerLog()")
    public void doAfterReturning(Object response) throws JsonProcessingException {
        if (response != null) {
            log.info("响应参数 : " + mapper.writeValueAsString(response));
        }
    }

}
